﻿package yii.db{

	import yii.*;
	import yii.base.*;
	import phpas3.*;
	import yii.db.*;
	import yii.db.schema.*;
	import yii.cache.dependencies.*;

	public class CDbConnection extends CApplicationComponent{


	public var connectionString:String;
	public var username:String = '';
	public var password:String = '';
	public var schemaCachingDuration:int = 0;
	public var schemaCachingExclude:Array = new Array();
	public var schemaCacheID:String = 'cache';
	public var queryCachingDuration:int = 0;
	public var queryCachingDependency:CCacheDependency;
	public var queryCachingCount:int = 0;
	public var queryCacheID:String = 'cache';
	public var autoConnect:Boolean = true;
	public var charset:String;
	public var emulatePrepare:Boolean;
	public var enableParamLogging:Boolean = false;
	public var enableProfiling:Boolean = false;
	public var tablePrefix:String;
	public var initSQLs:Array;
	public var pdoClass:String = 'PDO';
	private var _attributes:Array = new Array();
	private var _active:Boolean = false;
	private var _pdo:PDO;
	private var _transaction;
	private var _schema;

        public var driverMap = {
                pgsql:'CPgsqlSchema',    // PostgreSQL
                mysqli:'CMysqlSchema',   // MySQL
                mysql:'CMysqlSchema',    // MySQL
                sqlite:'yii.db.schema.sqlite.CSqliteSchema',  // sqlite 3
                sqlite2:'CSqliteSchema', // sqlite 2
                mssql:'CMssqlSchema',    // Mssql driver on windows hosts
                dblib:'CMssqlSchema',    // dblib drivers on linux (and maybe others os) hosts
                sqlsrv:'CMssqlSchema',   // Mssql
                oci:'COciSchema'        // Oracle driver
        }

	/**
	 * Constructor+
	 * Note, the DB connection is not established when this connection
	 * instance is created+ Set {@link setActive active} property to true
	 * to establish the connection+
	 * @param string $dsn The Data Source Name, or DSN, contains the information required to connect to the database+
	 * @param string $username The user name for the DSN string+
	 * @param string $password The password for the DSN string+
	 * @see http://www+php+net/manual/en/function+PDO-construct+php
	 */
	public function CDbConnection( $dsn='',$username='',$password='' ){
		this.connectionString=$dsn;
		this.username=$username;
		this.password=$password;
	}



	public function toString(){
		return "[object CDbConnection connectionString="+ this.connectionString +"]";
	}






	/**
	 * Opens DB connection if it is currently not
	 * @throws CException if connection fails
	 */
	protected function open():void{
		if( !this._pdo ){
			if( empty(this.connectionString) ){
				throw new Error( "CDbConnection.connectionString が空ではいけません。" );
			}
			try{
				this._pdo = this.createPdoInstance();
				this.initConnection( this._pdo );
				this._active = true;
			} catch( $e ){
				throw $e;
				//throw new Error( "CDbConnection DBの接続に失敗しました。connectionString="+ this.connectionString, $e );
			}
		}
	}














	/**
	 * Initializes the component+
	 * This method is required by {@link IApplicationComponent} and is invoked by application
	 * when the CDbConnection is used as an application component+
	 * If you override this method, make sure to call the parent implementation
	 * so that the component can be marked as initialized+
	 */
	public override function init():void{
		super.init();
		if(this.autoConnect)
			this.setActive(true);
	}



	/**
	 * Returns the ID of the last inserted row or sequence value+
	 * @param string $sequenceName name of the sequence object (required by some DBMS)
	 * @return string the row ID of the last row inserted, or the last value retrieved from the sequence object
	 * @see http://www+php+net/manual/en/function+PDO-lastInsertId+php
	 */
	public function getLastInsertID($sequenceName:String=''):int{
		this.setActive(true);
		return this._pdo.lastInsertId($sequenceName);
	}





	/**
	 * Quotes a string value for use in a query.
	 * @param string $str string to be quoted
	 * @return string the properly quoted string
	 * @see http://www.php.net/manual/en/function.PDO-quote.php
	 */
	public function quoteValue( $str:String ):String{
		if(is_int($str) || is_float($str))
			return $str;

		this.setActive( true );
		var $value:String = this._pdo.quote( $str );
		if( $value ){
			return $value;
		} else  {// the driver doesn't support quote (e.g. oci)
			return "'"+ addcslashes(str_replace("'", "''", $str), "\000\n\r\\\032") +"'";
		}
	}




	/**
	 * Returns the PDO instance+
	 * @return PDO the PDO instance, null if the connection is not established yet
	 */
	public function getPdoInstance():PDO{
		return this._pdo;
	}





	/**
	 * Initializes the open db connection+
	 * This method is invoked right after the db connection is established+
	 * The default implementation is to set the charset for MySQL and PostgreSQL database connections+
	 * @param PDO $pdo the PDO instance
	 */
	protected function initConnection( $pdo:PDO ):void{
		$pdo.setAttribute( PDO.ATTR_ERRMODE, PDO.ERRMODE_EXCEPTION );
		if( this.emulatePrepare!==null && PDO.ATTR_EMULATE_PREPARES ){
			$pdo.setAttribute( PDO.ATTR_EMULATE_PREPARES, this.emulatePrepare );
		}
		if( this.initSQLs ){
			for( var index in this.initSQLs ){
				var $sql = this.initSQLs[index];
				$pdo.exec( $sql );
			}
		}
	}


	/**
	 * Determines the PDO type for the specified PHP type+
	 * @param string $type The PHP type (obtained by gettype() call)+
	 * @return integer the corresponding PDO type
	 */
	public function getPdoType( $type:String ):int{
		var $map:Object = {
			'boolean': PDO.PARAM_BOOL,
			'integer': PDO.PARAM_INT,
			'string': PDO.PARAM_STR,
			'NULL': PDO.PARAM_NULL
		}
		return isset($map[$type]) ? $map[$type] : PDO.PARAM_STR;
	}



	/**
	 * Creates the PDO instance+
	 * When some functionalities are missing in the pdo driver, we may use
	 * an adapter class to provides them+
	 * @return PDO the pdo instance
	 * @since 1+0+4
	 */
	protected function createPdoInstance():PDO{
		var $pdoClass = this.pdoClass;
		return new PDO( this.connectionString, this.username, this.password, this._attributes );
	}





        protected function close(){
                //Yii::trace('Closing DB connection','system.db.CDbConnection');
                this._pdo=null;
                this._active=false;
                this._schema=null;
        }



        public function setActive( $value:Boolean ){
                if( $value != this._active ){
                        if($value)
                               	this.open();
                        else
                                this.close();
                }
        }






        public function getCommandBuilder():CDbCommandBuilder{
                return this.getSchema().getCommandBuilder();
        }


		public function createCommand( query:String=null ):CDbCommand{
			this.setActive( true );
			return new CDbCommand( this, query );
		}


        public function getDriverName():String{
        	return "sqlite";
        }

		public function getSchema():CDbSchema{
			if( this._schema ){
				return this._schema;
			} else {
				var driver:String = this.getDriverName();
				this._schema = Yii.createComponent( this.driverMap[driver], this )
				return this._schema;
			}
		}




	}
}